package cn.test.learnkotlin.v1

import kotlin.properties.Delegates
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

private class MDelegate {

    /**
     * 类委托
     */
    interface Base {
        fun print()
    }

    class BaseImpl(val x: Int) : Base {
        override fun print() {
            println(x)
        }
    }

    class Derived(b: Base) : Base by b

    fun fooBase() {
        val b = BaseImpl(10)
        Derived(b).print()
    }

    /**
     * 属性委托
     */
    class Example {
        var p: String by Delegate()
    }

    class Delegate {
        operator fun getValue(example: Example, property: KProperty<*>): String {
            return "$example,委托了${property.name}属性"
        }

        operator fun setValue(example: Example, property: KProperty<*>, s: String) {
            println("$example 的 ${property.name} 赋值为 $s")
        }
    }

    fun fooProperty() {
        val e = Example()
        println(e.p)

        e.p = "KKUp"
        println(e.p)
    }

    /**
     * 标准委托
     */
    fun fooLazy() {
        val lazyValue: String by lazy {
            println("lazy init")
            "a lazy str"
        }
        println(lazyValue)
        println(lazyValue)
    }

    /**
     * 可观察属性Observable
     */
    class User {
        var name: String by Delegates.observable("初始值") { property, oldValue, newValue ->
            println("${property.name} was set from \"$oldValue\" to \"$newValue\"")
        }
    }

    fun fooObservable() {
        val user = User()
        user.name = "first value"
        user.name = "second value"
    }

    /**
     * 把属性储存在映射中
     */
    class Site(map: Map<String, Any?>) {
        val name: String by map
        val url: String by map
    }

    fun fooMap() {
        val site = Site(mapOf("name" to "菜鸟教程", "url" to "www.runoob.com"))
        println(site.name)
        println(site.url)
    }

    class Site1(map: MutableMap<String, out Any?>) {
        val name: String by map
        val url: String by map
    }

    fun fooMutableMap() {
        val map = mutableMapOf("name" to "菜鸟教程", "url" to "www.runoob.com")
        val site = Site1(map)
        println("site name:${site.name} , siteUrl: ${site.url}")
        map["name"] = "runoob"
        println("site name:${site.name} , siteUrl: ${site.url}")
    }

    /**
     * Not Null
     */
    class NotNull {
        var notNullBar: String by Delegates.notNull()
    }

    fun fooNotNull() {
        val foo = NotNull()
        foo.notNullBar = "notNullBar"
        println(foo.notNullBar)
    }

    /**
     * 提供委托
     */
    class ResId {
        val image_id = "101"
        val text_id = "102"
    }

    class MyUi {
        val image: String by ResourceLoader(ResId())
        val text: String by ResourceLoader(ResId())
    }

    class ResourceLoader(id: ResId) {
        val d: ResId = id
        operator fun provideDelegate(
            thisRef: MyUi,
            p: KProperty<*>
        ): ReadOnlyProperty<MyUi, String> {
            if (p.name == "image" || p.name == "text") {
                return object : ReadOnlyProperty<MyUi, String> {
                    val id: ResId = d
                    override fun getValue(thisRef: MyUi, property: KProperty<*>): String {
                        return if (property.name == "image") {
                            property.name + "    " + id.image_id
                        } else {
                            property.name + "    " + id.text_id
                        }
                    }

                }
            } else {
                throw Exception("Error ${p.name}")
            }
        }
    }

    fun fooProvideProperty() {
        val myUi = MyUi()
        println(myUi.image)
        println(myUi.text)
    }

    fun main() {
        fooProvideProperty()
    }
}

fun main() {
    MDelegate().main()
}